#include "PLEdge.h"
#include "PLVertex.h"
#include "PLVertexFactory.h"

#include <iostream>

using std::cout;
using std::endl;

PLuint PLEdge::numEdges = 0;

/**
  *	Constructs a new PLEdge object with the given indices
  *
  * @param fromVertexIndex vertex index of the "From"-vertex
  * @param fromTexcoordIndex texcoord index of the "From"-vertex
  * @param toVertexIndex vertex index of the "To"-vertex
  * @param toTexcoordIndex texcoord index of the "To"-vertex
  * @param imageID image ID of the image, the PLEdge object corresponds to
  */
PLEdge::PLEdge( const PLuint &fromVertexIndex, const PLuint &fromTexcoordIndex,
	const PLuint &toVertexIndex, const PLuint &toTexcoordIndex,
	const PLuint &imageID )
{
	mFrom = PLVertexFactory::Get()->BorrowVertex( fromVertexIndex, fromTexcoordIndex, imageID );
	mTo = PLVertexFactory::Get()->BorrowVertex( toVertexIndex, toTexcoordIndex, imageID );
	mAdjacentEdge = 0;

	numEdges++;
}

/**
  *	Copy constructor
  *
  * @param edge const reference to the PLEdge object that is copied (PLVertex objects are never copied, they are only borrowed from the PLVertexFactory)
  */
PLEdge::PLEdge( const PLEdge &edge )
{
// 	PLuint from_vertex_index = mFrom->GetVertexIndex();
// 	PLuint to_vertex_index = mTo->GetVertexIndex();

	mFrom = PLVertexFactory::Get()->BorrowVertex( edge.mFrom->mVertexIndex, edge.mFrom->mTexcoordIndex, edge.mFrom->mTextureID );
	mTo = PLVertexFactory::Get()->BorrowVertex( edge.mTo->mVertexIndex, edge.mTo->mTexcoordIndex, edge.mTo->mTextureID );
	mAdjacentEdge = edge.mAdjacentEdge;

	numEdges++;
}

/**
  *	Destroys the PLEdge object
  */
PLEdge::~PLEdge( void )
{
	PLVertexFactory::Get()->ReturnVertex( mFrom );
	PLVertexFactory::Get()->ReturnVertex( mTo );
	
	numEdges--;
}

/**
  *	Returns a reference to the "From"-vertex
  *
  * @return reference to the "From"-vertex
  */
PLVertex &PLEdge::From( void )
{
	return *mFrom;
}

/**
  *	Returns the vertex index of the "From"-vertex
  *
  * @return vertex index of the "From"-vertex
  */
const PLuint &PLEdge::FromVertexIndex( void ) const
{
	return mFrom->mVertexIndex;
}

/**
  *	Returns the texcoord index of the "From"-vertex
  *
  * @return texcoord index of the "From"-vertex
  */
const PLuint &PLEdge::FromTexcoordIndex( void ) const
{
	return mFrom->mTexcoordIndex;
}

/**
  *	Returns a reference to the "To"-vertex
  *
  * @return reference to the "To"-vertex
  */
PLVertex &PLEdge::To( void )
{
	return *mTo;
}

/**
  *	Returns the vertex index of the "To"-vertex
  *
  * @return vertex index of the "To"-vertex
  */
const PLuint &PLEdge::ToVertexIndex( void ) const
{
	return mTo->mVertexIndex;
}

/**
  *	Returns the texcoord index of the "To"-vertex
  *
  * @return texcoord index of the "To"-vertex
  */
const PLuint &PLEdge::ToTexcoordIndex( void ) const
{
	return mTo->mTexcoordIndex;
}

/**
  *	Returns the number of currently instantiated PLEdge objects
  *
  * number of currently instantiated PLEdge objects
  */
const PLuint &PLEdge::GetNumEdges( void )
{
	return numEdges;
}

/**
  *	Returns a const pointer to the adjacent PLEdge object. This pointer is 0
  * when no such PLEdge object exists
  *
  * @return const pointer to the adjacent PLEdge object
  */
const PLEdge *PLEdge::GetAdjacentEdge( void )
{
	return mAdjacentEdge;
}

/**
  *	Sets the adjacent PLEdge object. The object is not copied, just the pointer
  * is stored.
  *
  * @param adjacentEdge pointer to the adjacent PLEdge object
  */
void PLEdge::SetAdjacentEdge( PLEdge *adjacentEdge )
{
	mAdjacentEdge = adjacentEdge;
}

/**
  *	Overloaded ()-operator for the PLEdgeVICompare-Class, whose instances are
  * used as Compare-objects in stl containers.
  *
  * @param first const reference to the first PLEdge object in the comparison
  * @param second const reference to the second PLEdge object in the comparison
  * @return true, when vertex indices in first are smaller than in second, false otherwise
  */
bool PLEdge::PLEdgeVICompare::operator()(const PLEdge &first, const PLEdge &second) const
{
	PLEdge::PLEdgeVIPCompare compare;
	return compare( &first, &second );
}

/**
  *	Overloaded ()-operator for the PLEdgeVIPCompare-Class, whose instances are
  * used as Compare-objects in stl containers.
  *
  * @param first const pointer to the first PLEdge object in the comparison
  * @param second const pointer to the second PLEdge object in the comparison
  * @return true, when vertex indices in first are smaller than in second, false otherwise
  */
bool PLEdge::PLEdgeVIPCompare::operator()(const PLEdge *first, const PLEdge *second) const
{
	PLuint begin[2] = { first->mFrom->mVertexIndex, first->mTo->mVertexIndex };
	PLuint end[2] = { second->mFrom->mVertexIndex, second->mTo->mVertexIndex };
	PLuint helper;

	if (begin[0] > begin[1])
	{
		helper = begin[0];
		begin[0] = begin[1];
		begin[1] = helper;
	}

	if (end[0] > end[1])
	{
		helper = end[0];
		end[0] = end[1];
		end[1] = helper;
	}

	if (begin[0] < end[0])
	{
		return true;
	}
	else if (begin[0] > end[0])
	{
		return false;
	}
	else
	{
		if (begin[1] < end[1])
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}

/**
  *	Overloaded ()-operator for the PLEdgeVIAndTICompare-Class, whose instances are
  * used as Compare-objects in stl containers.
  *
  * @param first const reference to the first PLEdge object in the comparison
  * @param second const reference to the second PLEdge object in the comparison
  * @return true, when vertex indices and texture IDs in first are smaller than in second, false otherwise
  */
bool PLEdge::PLEdgeVIAndTICompare::operator()(const PLEdge &first, const PLEdge &second) const
{
	PLEdge::PLEdgeVIAndTIPCompare compare;
	return compare( &first, &second );
}

/**
  *	Overloaded ()-operator for the PLEdgeVIAndTIPCompare-Class, whose instances are
  * used as Compare-objects in stl containers.
  *
  * @param first const pointer to the first PLEdge object in the comparison
  * @param second const pointer to the second PLEdge object in the comparison
  * @return true, when vertex indices and texture IDs in first are smaller than in second, false otherwise
  */
bool PLEdge::PLEdgeVIAndTIPCompare::operator()(const PLEdge *first, const PLEdge *second) const
{
	const PLVertex *begin[2] = { first->mFrom, first->mTo };
	const PLVertex *end[2] = { second->mFrom, second->mTo };
	const PLVertex *helper;

	if (begin[0]->mVertexIndex > begin[1]->mVertexIndex)
	{
		helper = begin[0];
		begin[0] = begin[1];
		begin[1] = helper;
	}

	if (end[0]->mVertexIndex > end[1]->mVertexIndex)
	{
		helper = end[0];
		end[0] = end[1];
		end[1] = helper;
	}

	if (begin[0]->mVertexIndex < end[0]->mVertexIndex)
	{
		return true;
	}
	else if (begin[0]->mVertexIndex > end[0]->mVertexIndex)
	{
		return false;
	}
	else
	{
		if (begin[1]->mVertexIndex < end[1]->mVertexIndex)
		{
			return true;
		}
		else if (begin[1]->mVertexIndex > end[1]->mVertexIndex)
		{
			return false;
		}
		else
		{
			if (begin[0]->mTextureID < end[0]->mTextureID)
			{
				return true;
			}

			return false;
		}
	}
}

/**
  *	Overloaded ()-operator for the PLEdgeJustFromVICompare-Class, whose instances are
  * used as Compare-objects in stl containers.
  *
  * @param first const reference to the first PLEdge object in the comparison
  * @param second const reference to the second PLEdge object in the comparison
  * @return true, when the "From" vertex index in first is smaller than in second, false otherwise
  */
bool PLEdge::PLEdgeJustFromVICompare::operator()(const PLEdge &first, const PLEdge &second) const
{
	PLEdge::PLEdgeVIAndTIPCompare compare;
	return compare( &first, &second );
}

/**
  *	Overloaded ()-operator for the PLEdgeJustFromVIPCompare-Class, whose instances are
  * used as Compare-objects in stl containers.
  *
  * @param first const pointer to the first PLEdge object in the comparison
  * @param second const pointer to the second PLEdge object in the comparison
  * @return true, when the "From" vertex index in first is smaller than in second, false otherwise
  */
bool PLEdge::PLEdgeJustFromVIPCompare::operator()(const PLEdge *first, const PLEdge *second) const
{
	if (first->mFrom->mVertexIndex < second->mFrom->mVertexIndex)
		return true;

	return false;
}